# 导入蓝图对象
import random
from datetime import datetime

from flask import session
from sqlalchemy import or_

from info.libs.yuntongxun.sms import CCP
from info.models import User
from . import passport_blu
# 导入captcha扩展实现图片验证码的生成
from info.utils.captcha.captcha import captcha
# 导入flask内置的对象
from flask import request, jsonify, current_app, make_response
# 导入自定义的状态码
from info.utils.response_code import RET
# 导入redis实例,# 导入常量配置文件
from info import redis_store, constants, db
# 导入正则模块
import re


@passport_blu.route('/image_code')
def generate_image_code():
    """
    生成图片验证码
    1、获取前端生成的UUID；
    2、调用captcha扩展，来生成图片验证码，name,image,text
    3、把图片验证码的内容text，存储到redis数据库中；把uuid作为扩展名保存图片验证码的内容
    4、使用make_response返回图片给前端；
    5、修改默认响应的headers改成Content-Type = image/jpg

    :return:
    """
    # 获取参数
    image_code_id = request.args.get('image_code_id')
    # 校验参数存在
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 生成图片验证码
    name, text, image = captcha.generate_captcha()
    print('----', text)
    # 在服务器redis数据库中保存图片验证码
    try:
        redis_store.setex('ImageCode_' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        # 使用应用上下文记录操作redis数据库的错误信息
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保存图片验证码失败')
    # 如果没有发生异常，直接返回图片
    else:
        # 使用响应对象返回图片本身
        response = make_response(image)
        # 修改响应头，改成图片格式
        response.headers['Content-Type'] = 'image/jpg'
        return response


@passport_blu.route('/sms_code', methods=['POST'])
def send_sms_code():
    #     获取参数
    param_data = request.json
    #     获取用户输入的手机号
    mobile = param_data.get("mobile")
    #     获取用户输入的图片验证码
    image_code = param_data.get("image_code")
    #     获取图片验证码编号
    image_code_id = param_data.get("image_code_id")
    #     校验参数的完整性
    if not all([mobile, image_code, image_code_id]):
        return jsonify(error=RET.PARAMERR, errmsg="参数不完整")
    # 根据正则表达式验证手机号是否正确
    if not re.match("^1[35678][0-9]{9}$", mobile):
        return jsonify(error=RET.PARAMERR, errmsg="手机号格式错误")
    # 验证手机号是否已经注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(error=RET.DBERR, errmsg="数据查询错误")
    if user:
        return jsonify(error=RET.DATAEXIST, errmsg="手机号已经注册过")

    # 根据uuid key获取图片验证码
    try:
        redis_image_code = redis_store.get('ImageCode_' + image_code_id)
        #     因为python3中从redis数据库中获取到的都是bytes类型 所以进行解码
        if redis_image_code:
            # redis_image_code = redis_image_code.decode()
            #             为了防止用户暴力测试 解码完立即删除redis中的数据
            redis_store.delete('ImageCode_' + image_code_id)

    except Exception as e:
        current_app.logger.error(e)
        return jsonify(error=RET.DATAERR, errmsg="图片验证码查询错误")
    if not redis_image_code:
        return jsonify(error=RET.DATAERR, errmsg="图片验证码已经过期")

    if redis_image_code.lower() != image_code.lower():
        return jsonify(error=RET.PARAMERR, errmsg="图片验证码输入错误")
    # 如果验证全部成功 通过random.randint生成六位随机数
    result = random.randint(0, 999999)
    # 不够6位 0部位
    sms_code = "%06d" % result
    #     调用云通讯发送短信验证码
    result = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], "1")
    if result != 0:
        return jsonify(error=RET.THIRDERR, errmsg="发送短信验证码错误")
    try:
        redis_store.setex("SMS_" + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(error=RET.DATAERR, errmsg="数据保存错误")
    return jsonify(error=RET.OK, errmsg="发送短信验证码成功")


@passport_blu.route('/register', methods=['POST'])
def register():
    """
    注册用户
    1、获取参数：mobile,sms_code,password
    2、校验参数的完整性
    3、校验手机号的格式
    4、获取本地存储的真实短信验证码
    5、校验获取结果
    6、先比较短信是否一致，如果不一致直接终止程序运行
    7、再删除redis中的短信验证码
    8、构造模型类的实例对象
    9、user = User();
    # 对密码进行加密存储
    user.password = password
    10、提交用户数据到mysql数据库中；
    11、提交数据成功后，把用户的基本信息mobile,id,nick_name，缓存到redis中；
    12、返回结果
    :return:
    """
    # 获取需要的参数
    real_dict = request.json
    mobile = real_dict.get("mobile")
    sms_code = real_dict.get("sms_code")
    password = real_dict.get("password")
    # 校验参数的完整性
    if not all([mobile, sms_code, password]):
        return jsonify(error=RET.PARAMERR, errmsg="参数不完整")
    # 验证手机号的格式是否正确
    if not re.match("^1[35678][0-9]{9}$", mobile):
        return jsonify(error=RET.DATAERR, errmsg="手机号格式错误")
    # 验证手机号是否已经被注册过
    try:
        user = User.query.filter_by(mobile=mobile).first()
        if user:
            return jsonify(error=RET.DATAEXIST, errmsg="手机号已经注册过")
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(error=RET.DBERR, errmsg="手机号查询错误")
        # 验证用户输入的短信验证码是否正确
    try:
        redis_sms_code = redis_store.get("SMS_" + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(error=RET.DBERR, errmsg="短信验证码获取错误")
    if not redis_sms_code:
        return jsonify(error=RET.NODATA, errmsg="短信验证码已经过期")
    if sms_code != redis_sms_code:
        return jsonify(error=RET.PARAMERR, errmsg="短信验证码输入错误")
    # 删除短信验证码
    try:
        redis_store.delete("SMS_" + mobile)
    except Exception as  e:
        current_app.logger.error(e)
    # 创建模型类对象
    user = User()
    user.nick_name = mobile
    user.mobile = mobile
    user.password = password
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(error=RET.DATAERR, errmsg="数据保存错误")
    # 保存登录信息
    session["user.id"] = user.id
    session["user.nick_name"] = user.nick_name
    session["user.mobile"] = user.mobile
    #     返回注册结果
    return jsonify(error=RET.OK, errmsg="注册成功")


# 登录的实现
@passport_blu.route("/login", methods=["POST"])
def login():
    # 获取参数，校验参数的完整性
    json_data = request.json
    mobile = json_data.get("mobile")
    nick_name = json_data.get("nick_name")
    password = json_data.get("password")
    if not all([mobile, password] or [nick_name, password]):
        return jsonify(error=RET.PARAMERR, errmsg="参数不完整")
    # 校验手机号的格式是否正确
    if not re.match("^1[35678][0-9]{9}$", mobile):
        return jsonify(error=RET.DATAERR, errmsg="手机号格式错误")
    # 验证手机号是否已经被注册过
    try:
        user = User.query.filter_by(or_(mobile=mobile, nick_name=nick_name)).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(error=RET.DBERR, errmsg="手机号查询错误")
    if not user:
        return jsonify(error=RET.USERERR, errmsg="手机号还没有注册，请先注册手机号")
    if not user.check_passowrd(password):
        return jsonify(errno=RET.PWDERR, errmsg="密码错误")
        # 保存登录状态
    session["user.id"] = user.id
    session["user.nick_name"] = user.nick_name
    session["user.mobile"] = user.mobile
    # 记录用户最后一次登录时间
    user.last_login = datetime.now()
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
    return jsonify(error=RET.OK,errmsg="用户登录成功")
#

